//
// Created by none98 on 2021/9/16.
//
#include <spdlog/spdlog.h>
#include "GameServer.h"
#include "Dispatcher.h"
#include "services/LoginService.h"
#include "Context.h"
#include "PlayerBin.h"
#include "boost/asio.hpp"

GameServer::GameServer():
    tcpServer(new TcpServer),
    dispatcher(new Dispatcher(std::bind(&GameServer::SubmitTask,this,std::placeholders::_1)))
{
    tcpServer->SetKeepAlive(true);
}

/*
 *  struct message{
 *      int length
 *      int type
 *      char [protobuf_length]
 *  }
 * */

void GameServer::OnMessage(TcpConnectionPtr conn, Buffer *inputBuffer) {
    dispatcher->Dispatch(conn,inputBuffer);
}

void GameServer::OnConnection(TcpConnectionPtr conn) {
    conn->SetContext(std::make_shared<Context>(this));
}

void GameServer::OnClose(TcpConnectionPtr conn) {
    Context* context =static_cast<Context*>( conn->GetContext());
    context->Synchronize();
    {
        std::unique_lock<std::mutex> lock(consMutex);
        if(connections[context->GetUid()]==conn)
            connections.erase(context->GetUid());
    }
}


void GameServer::Login(long uid, TcpConnectionPtr conn) {
    TcpConnectionPtr old;
    {
        std::unique_lock<std::mutex> lock(consMutex);
        if (connections.find(uid) == connections.end()) {
            connections[uid] = conn;
        } else {
            old = connections[uid];
            connections[uid] = conn;
        }
    }
    if(old) old->Close();
}


void GameServer::Start(const std::string &address, int port) {
    tcpServer->OnConnection(std::bind(&GameServer::OnConnection,this,std::placeholders::_1));
    tcpServer->OnMessage(std::bind(&GameServer::OnMessage,this,std::placeholders::_1,std::placeholders::_2));
    tcpServer->OnClose(std::bind(&GameServer::OnClose,this,std::placeholders::_1));
    spdlog::info("server start at {}:{}",address,port);
    tcpServer->Start(address,port);
}

void GameServer::SubmitTask(const std::function<void()> &func) {
    boost::asio::post(pool,func);
}

GameServer::~GameServer() {

}

void GameServer::Handle(int type, Service *service) {
    dispatcher->RegisterHandler(type,service);
}

void GameServer::SetDatabase(const std::string &hostname, const std::string &username, const std::string &password) {
    dbConnectionsPool.reset(new DatabaseConnPool);
    dbConnectionsPool->InitPool(hostname,username,password);
}




